import * as d3 from 'd3'
export class MultiBarChart {
    divId = ''
    data = []
    xLabel = ''
    yLabel = ''
    title = ''
    categortLabel = ''
    itemsName = []
    chart = {}
    color = d3.scaleOrdinal(d3.schemeCategory10)

    constructor (divId) {
      this.divId = divId
    }

    draw () {
      this.initChart()
      this.initAxis()
      this.drawLabel()
      this.drawLegend()
      this.drawStackBar()
    }

    update () {

    }

    initChart () {
      this.chart.padding = {
        left: 50,
        right: 50,
        top: 20,
        bottom: 25
      }
      this.chart.divHeight = document.getElementById(this.divId).offsetHeight -
          this.chart.padding.top -
          this.chart.padding.bottom
      this.chart.divWidth = document.getElementById(this.divId).offsetWidth -
          this.chart.padding.left -
          this.chart.padding.right

      this.basicRadius = Math.min(this.chart.divHeight, this.chart.divWidth) / 2

      this.chart.svg = d3
        .select('#' + this.divId)
        .append('svg')
        .attr('width', this.chart.divWidth +
            this.chart.padding.left +
            this.chart.padding.right
        )
        .attr('height', this.chart.divHeight +
            this.chart.padding.top +
            this.chart.padding.bottom
        )
        .attr('class', 'svg_chart')
    }

    initAxis () {
      this.chart.xScale = d3.scaleBand()
        .domain(this.data.map(d => d.date))
        .range([this.chart.padding.left, this.chart.divWidth])

      this.chart.barPadding = this.chart.xScale.bandwidth() * 0.9
      // 定义y轴的比例尺
      this.chart.yScale = d3.scaleLinear()
        .domain([0, d3.max(this.data.map(d => Math.max(d.food, d.transportation, d.education)))])
        .range([this.chart.divHeight, this.chart.padding.top])

      // 定义x轴
      this.chart.xAxis = d3.axisBottom()
        .scale(this.chart.xScale)
      // 定义y轴
      this.chart.yAxis = d3.axisLeft()
        .scale(this.chart.yScale)

      this.chart.svg.append('g')
        .attr('class', 'xAxis')
        .attr('transform', 'translate(0,' +
          this.chart.divHeight + ')')
        .call(this.chart.xAxis)

      this.chart.svg.append('g')
        .attr('class', 'yAxis')
        .attr('transform', 'translate(' + this.chart.padding.left + ')')
        .call(this.chart.yAxis)
    }

    drawStackBar () {
      let rectWidth = this.chart.barPadding / 3
      let t = d3.transition()
        .duration(750)
      let groups = this.chart.svg.selectAll('.group')
        .data(this.data)

      groups.selectAll('rect')
        .attr('x', (d, i) => this.xScale(d.position) + i * rectWidth)
        .attr('y', d => this.chart.yScale(d[0]))
        .attr('width', rectWidth)
        .attr('height', 0)
        .transition(t)
        .attr('y', d => this.chart.yScale(d.value))
        .attr('height', d => this.chart.yScale(d.value))

      let groupEnter = groups.enter()
        .append('g')
        .attr('class', 'group')
        .selectAll('.bar')
        .data(d => {
          let cate = []
          for (let i = 0; i < this.itemsName.length; ++i) {
            cate.push({
              name: this.itemsName[i],
              value: d[this.itemsName[i]],
              position: d[this.categortLabel]
            })
          }
          return cate
        })
        .enter()
        .append('g')
        .attr('class', 'bar')

      groupEnter.append('rect')
        .attr('x', (d, i) => {
          return this.chart.xScale(d.position) + i * rectWidth
        })
        .attr('y', d => {
          return this.chart.divHeight
        })
        .attr('width', rectWidth * 0.9)
        .attr('height', 0)
        .style('fill', (_, i) => this.color(i))
        .transition(t)
        .attr('y', d => this.chart.yScale(d.value))
        .attr('height', d => this.chart.divHeight - this.chart.yScale(d.value))

      groupEnter.append('text')
        .attr('x', (d, i) => {
          return this.chart.xScale(d.position) + i * rectWidth + rectWidth * 0.4
        })
        .attr('y', d => {
          return this.chart.divHeight
        })
        .style('font-size', 1e-6)
        .text(d => d.value)
        .transition(t)
        .attr('y', d => this.chart.yScale(d.value) - 10)
        .style('font-size', 12)

      groups.exit()
        .selectAll('rect')
        .transition(t)
        .attr('y', d => this.chart.yScale(d.value))
        .attr('height', 0)
        .remove()
    }

    drawLabel () {
      // 标题
      this.chart.svg
        .append('text')
        .attr('x', this.chart.divWidth / 2 - this.title.length)
        .attr('y', this.chart.divHeight + this.chart.padding.bottom * 1.7)
        .text(this.title)
      // y轴
      this.chart.svg
        .append('text')
        .attr('x', this.chart.padding.left)
        .attr('y', this.chart.padding.top - 5)
        .text(this.yLabel)
      // x轴
      this.chart.svg
        .append('text')
        .attr('x', this.chart.divWidth + 5)
        .attr('y', this.chart.divHeight)
        .text(this.xLabel)
    }

    drawLegend () {
      let legendWidth = 15
      let legendHeight = 15
      let legends = this.chart.svg
        .selectAll('.legend')
        .data(this.itemsName)
      let legendEnter = legends.enter()
        .append('g')
        .attr('class', 'legend')

      legendEnter.append('rect')
        .attr('x', this.chart.divWidth + 5)
        .attr('y', (d, i) => this.chart.padding.top + legendHeight * i)
        .attr('width', 0)
        .attr('height', legendHeight - 5)
        .style('fill', (d, i) => this.color(i))

      legendEnter.append('text')
        .attr('x', this.chart.divWidth + legendWidth * 1.3 + 5)
        .attr('y', (d, i) => this.chart.padding.top + legendHeight * i + legendHeight / 2)
        .text(String)
        .style('font-size', 1e-6)

      let legendUpdate = legendEnter.merge(legends)
      legendUpdate.select('rect')
        .transition()
        .duration(750)
        .attr('width', legendWidth)

      legendUpdate.select('text')
        .transition()
        .duration(750)
        .style('font-size', 10)

      let legendExit = legends.exit()
        .transition()
        .duration(750)
        .remove()

      legendExit.select('rect')
        .attr('width', 0)

      legendExit.select('text')
        .style('stroke-opacity', 1e-6)
    }
}
